package com.common.atom.seal.util;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import org.apache.commons.lang3.StringUtils;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.Properties;

/**
 * description: SealTemplate <br>
 * date: 2023/4/14  <br>
 * author: zss <br>
 * version: 1.0.0 <br>
 */
public class SealTemplate {


    public static BufferedImage draw(BufferedImage bufferedImage, JSONObject templateRule, Map<String, Object> parameters, Properties fontTable, double alpha) throws Exception {
        int width = templateRule.getIntValue("width");
        int height = templateRule.getIntValue("height");
        int fontType = Integer.parseInt(parameters.get("fontType").toString());
        if (bufferedImage == null) {
            bufferedImage = SealUtils.createTransparentBufferedImage(width == 0 ? 1 : width, height == 0 ? 1 : height);
        } else {
            width = bufferedImage.getWidth();
            height = bufferedImage.getHeight();
        }

        Color color = createColor(String.valueOf(parameters.get("color")), alpha);
        Graphics2D graphics2d = SealUtils.getSmoothGraphics2D(bufferedImage);
        int offset;
        // 底边字与内边最小距离
        offset = templateRule.getIntValue("offset");
        JSONArray attachedObjects = templateRule.getJSONArray("attachedObjects");

        int border = 8;
        if (attachedObjects != null) {
            for (int i = 0; i < attachedObjects.size(); i++) {
                JSONObject attachedObject = attachedObjects.getJSONObject(i);
                String attachedType = attachedObject.getString("attachedType");
                graphics2d.setColor(color);
                int fontSize = attachedObject.getIntValue("fontSize");
                Font f = null;
                if (fontType == 1) {
                    f = new Font("Microsoft YaHei", Font.BOLD, fontSize);
                } else if (fontType == 2) {
                    f = new Font("SimHei", Font.BOLD, fontSize);
                } else if (fontType == 3) {
                    f = new Font("SimSun", Font.BOLD, fontSize);
                } else if (fontType == 4) {
                    f = new Font("华文行楷", Font.BOLD, fontSize);
                } else if (fontType == 5) {
                    f = new Font("方正舒体", Font.BOLD, fontSize);
                } else {
                    f = new Font("Microsoft YaHei", Font.BOLD, fontSize);
                }

                if ("Circle".equals(attachedType)) {
                    int w = attachedObject.getIntValue("width", width);
                    int h = attachedObject.getIntValue("height", height);

                    //int offset = attachedObject.optInt("offset", 2);

                    offset = attachedObject.getIntValue("offset", 2);
                    SealUtils.drawBorderedCircle(graphics2d, w, h, border, offset);
                } else if ("RoundRect".equals(attachedType)) {
                    int w = attachedObject.getIntValue("width", width);
                    int h = attachedObject.getIntValue("height", height);

                    //int offset = attachedObject.optInt("offset", 1);

                    offset = attachedObject.getIntValue("offset", 1);
                    int arcWidth = attachedObject.getIntValue("arcWidth", 20);
                    int arcHeight = attachedObject.getIntValue("arcHeight", 20);
                    SealUtils.drawBorderedRoundRect(graphics2d, w, h, border, arcWidth, arcHeight, offset);
                } else if ("Pentagram".equals(attachedType)) {
                    int w = attachedObject.getIntValue("width", width);
                    int h = attachedObject.getIntValue("height", height);
                    int pentagramRadius = 70;
                    SealUtils.drawPentagram(graphics2d, w / 2, h / 2, pentagramRadius);
                } else if ("Rectangle".equals(attachedType)) {
                    int w = attachedObject.getIntValue("width", width);
                    int h = attachedObject.getIntValue("height", height);

//int offset = attachedObject.optInt("offset", 0);

                    offset = attachedObject.getIntValue("offset", 0);
                    graphics2d.drawRect(width / 2 + border / 2 - w / 2 + offset, height / 2 + border / 2 - h / 2 + offset, w - border - offset * 2, h - border - offset * 2);
                } else if ("Text".equals(attachedType)) {
                    String objectClass = attachedObject.getString("objectClass");
                    String objectName = attachedObject.getString("objectName");
                    Object objectValue = attachedObject.get("objectValue");
                    if ((objectValue == null) && (parameters != null)) {
                        objectValue = parameters.get(objectName);
                    }
                    String objectText = null;
                    if ("Date".equals(objectClass)) {
                        Date dateObjectValue = null;
                        if ((objectValue instanceof Date)) {
                            dateObjectValue = (Date) objectValue;
                        } else if ((objectValue instanceof String)) {
                            String ISO8601_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ssZ";
                            SimpleDateFormat simpleDateFormat = new SimpleDateFormat(ISO8601_DATE_FORMAT);
                            dateObjectValue = simpleDateFormat.parse((String) objectValue);
                        } else if ((objectValue instanceof Integer)) {
                            dateObjectValue = new Date(((Long) objectValue).longValue());
                        }
                        String dateFormat = attachedObject.getString("dateFormat");
                        if (dateFormat == null) {
                            dateFormat = "yyyy-MM-dd";
                        }
                        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(dateFormat);
                        objectText = simpleDateFormat.format(dateObjectValue);
                    } else {
                        if (!"String".equals(objectClass)) {
                            continue;
                        }
                        objectText = (String) objectValue;
                        String stringTransform = attachedObject.getString("stringTransform");
                        if ("lowerCase".equals(stringTransform)) {
                            objectText = objectText.toLowerCase();
                        } else if ("upperCase".equals(stringTransform)) {
                            objectText = objectText.toUpperCase();
                        }

                    }

                    if (objectText != null) {
                        String fontFamily = attachedObject.getString("fontFamily");
                        String fontWeight = attachedObject.getString("fontWeight");

//int fontSize = attachedObject.optInt("fontSize");

                        int fontStyle = "bold".equals(fontWeight) ? 1 : 0;
                        fontStyle = attachedObject.getBooleanValue("fontItalic") ? fontStyle | 0x2 : fontStyle;

//Font textFont = fontPath != null ? getFont(fontPath, fontFamily, fontStyle, fontSize) : new Font(fontFamily, fontStyle, fontSize);
//Font textFont = new Font(fontFamily, fontStyle, fontSize);

                        Font textFont = f;
                        String textStyle = attachedObject.getString("textStyle");

                        if (("VerticalHorizontalCentered".equals(textStyle)) || ("BelowHorizontalCentered".equals(textStyle)) ||
                                ("HorizontalCentered"
                                        .equals(textStyle))) {
                            int wordSpacing = attachedObject.getIntValue("wordSpacing");
                            int textY = 0;
                            int offsetY = attachedObject.getIntValue("offsetY", 0);

                            int upperTextMax = 6;
                            int upperTextLength = objectValue.toString().length();
                            if (upperTextLength > upperTextMax) {
                                textFont = SealUtils.scaleFont(textFont, (double) upperTextMax / upperTextLength, 2);
                            } else {
                                textFont = SealUtils.scaleFont(textFont, 1, 2);
                            }
                            FontMetrics fontMetrics = SealUtils.createFontMetrics(textFont);
                            if ((width == 0) && (height == 0) && (bufferedImage.getWidth() == 1) &&
                                    (bufferedImage
                                            .getHeight() == 1)) {
                                width = fontMetrics.stringWidth(objectText);
                                height = fontMetrics.getHeight();
                                bufferedImage = SealUtils.resizeCanvas(bufferedImage, width, height, 5);
                                graphics2d = SealUtils.getSmoothGraphics2D(bufferedImage);
                                graphics2d.setColor(color);
                            }
                            if ("VerticalHorizontalCentered".equals(textStyle)) {
                                textY = height / 2 + (fontMetrics.getHeight() / 2 - fontMetrics.getDescent());
                            } else if ("BelowHorizontalCentered".equals(textStyle)) {
                                textY = height + fontMetrics.getAscent();
                            } else if ("HorizontalCentered".equals(textStyle)) {
                                textY = attachedObject.getIntValue("textY");
                                if (textY == 0) {
                                    textY = fontMetrics.getAscent();
                                }
                            }
                            textY += offsetY;

                            if ((fontMetrics.stringWidth(objectText) > width) || (textY + fontMetrics.getDescent() > height)) {
                                width = fontMetrics.stringWidth(objectText) > width ? fontMetrics.stringWidth(objectText) : width;
                                height = textY + fontMetrics.getDescent() > height ? textY + fontMetrics.getDescent() : height;
                                bufferedImage = SealUtils.resizeCanvas(bufferedImage, width, height, 8);
                                graphics2d = SealUtils.getSmoothGraphics2D(bufferedImage);
                                graphics2d.setColor(color);
                            }
                            SealUtils.drawHorizontalCenteredText2(graphics2d, width, height, objectText, textFont, textY, wordSpacing);
                        } else if ("ClockwiseFan".equals(textStyle)) {
                            int fanRadius = attachedObject.getIntValue("fanRadius", 105);
                            double fanAngle = attachedObject.getDoubleValue("fanAngle"); //, 240.0D
                            JSONObject fanAngleFunc = attachedObject.getJSONObject("fanAngleFunc");
                            if (fanAngleFunc != null) {
                                String script = fanAngleFunc.getString("script"); //, "0"
                                Object result = eval(script, parameters);
                                fanAngle = Double.parseDouble(result.toString());
                            }
                            int upperTextMax = 18;
                            int upperTextLength = objectValue.toString().length();
                            if (upperTextLength > upperTextMax) {
                                textFont = SealUtils.scaleFont(textFont, (double) upperTextMax / upperTextLength, 1.8);
                            } else {
                                textFont = SealUtils.scaleFont(textFont, 1, 1.8);
                            }
                            SealUtils.drawClockwiseFanText(graphics2d, width, height, objectText, textFont, fanRadius - 20, fanAngle);
                        } else if ("AnticlockwiseFan".equals(textStyle)) {
                            if (!StringUtils.isBlank(objectText)) {
                                int fanRadius = attachedObject.getIntValue("fanRadius");
                                double fanAngle = attachedObject.getDoubleValue("fanAngle");
                                JSONObject fanAngleFunc = attachedObject.getJSONObject("fanAngleFunc");
                                if (fanAngleFunc != null) {
                                    String script = fanAngleFunc.getString("script");//, "0"
                                    Object result = eval(script, parameters);
                                    fanAngle = Double.parseDouble(result.toString());
                                }
                                int[] textLen = calcTextLength(textFont, objectText, width, fanAngle);
                                //int upperTextMax = 6;
                                //int upperTextLength = objectValue.toString().length();
                                int upperTextMax = textLen[1];
                                int upperTextLength = textLen[0];
                                fanAngle = textLen[2];

                                if (upperTextLength > upperTextMax) {
                                    textFont = SealUtils.scaleFont(textFont, (double) upperTextMax / upperTextLength, 1.2);
                                } else {
                                    textFont = SealUtils.scaleFont(textFont, 1, 1.2);
                                }
                                SealUtils.drawAnticlockwiseFanText(graphics2d, width, height, objectText, textFont, fanRadius, fanAngle);
                            }
                        }
                    }
                }
            }
        }
        graphics2d.dispose();
        return bufferedImage;
    }

    // 实际的字符的长度  弧度的长度  弧度
    private static int[] calcTextLength(java.awt.Font textFont, String objectText, int width, double Angle) {
        int[] result = new int[3];
        //扇形角度
        double fanAngle = Angle;
        FontMetrics fontMetrics = SealUtils.createFontMetrics(textFont);
        float wHeight = fontMetrics.getHeight();
        int strWidth = fontMetrics.stringWidth(objectText);
        result[0] = strWidth;
        float perimeter = (float) (3.1415926 * width);
        float drawLenght = (float) (fanAngle / 360) * perimeter;
        result[1] = ((int) drawLenght) + 1;
        if (result[0] >= result[1]) {
            result[2] = ((int) Angle);
        } else {
            float a = ((float) result[0] / (float) result[1]) * (float) Angle;
            result[2] = Math.round(a + 1);
        }
        return result;
    }

    public static Color createColor(String colorStr, double alphax) {
        Color color = null;

        int alpha = (int) Math.round(255 * alphax / 10);
        if (colorStr != null) {
            if (colorStr.startsWith("#")) {
                colorStr = colorStr.substring(1);
                int fontR = HexUtils.decode(colorStr.substring(0, 2).getBytes(StandardCharsets.UTF_8))[0];
                fontR = fontR < 0 ? fontR + 256 : fontR;
                int fontG = HexUtils.decode(colorStr.substring(2, 4).getBytes(StandardCharsets.UTF_8))[0];
                fontG = fontG < 0 ? fontG + 256 : fontG;
                int fontB = HexUtils.decode(colorStr.substring(4, 6).getBytes(StandardCharsets.UTF_8))[0];
                fontB = fontB < 0 ? fontB + 256 : fontB;
                color = new Color(fontR, fontG, fontB, alpha);
            } else {
                switch (colorStr) {
                    case "1":
                        color = new Color(230, 0, 18, alpha);
                        break;
                    case "2":// 绿色
                        color = new Color(18, 230, 18, alpha); // 设置画笔颜色
                        break;
                    case "3":// 蓝色
                        color = new Color(18, 0, 230, alpha); // 设置画笔颜色
                        break;
                    case "4":// 黑色
                        color = new Color(0, 0, 0, alpha); // 设置画笔颜色
                        break;
                    default:
                        color = new Color(230, 0, 18, alpha);
                        break;
                }
            }
        }
        return color;
    }

//    public static Object eval(String script, Map<String, Object> parameters) throws ScriptException {
//        ScriptEngineManager manager = new ScriptEngineManager();
//        ScriptEngine engine = manager.getEngineByName("js");
//        if (parameters != null) {
//            for (Map.Entry entry : parameters.entrySet()) {
//                if (entry.getValue() != null) {
//                    script = script.replaceAll("\\$\\{" + (String) entry.getKey() + "\\}", entry.getValue().toString());
//                }
//            }
//        }
//        Object result = engine.eval(script);
//        return result;
//    }

    public static Object eval(String script, Map<String, Object> parameters) {
        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine engine = manager.getEngineByName("js");
        if (parameters != null) {
            for (Map.Entry entry : parameters.entrySet()) {
                if (entry.getValue() != null) {
                    try {
                        script = script.replaceAll("\\$\\{" + (String) entry.getKey() + "\\}", entry.getValue().toString());
                    } catch (Exception ex) {
                        //var len='${content3}'.length;if(len<=12){60;}else if(len==13){90;}else if(len==14){120;}else{150;}
                        if ((entry.getValue()).getClass().equals(String.class)) {
                            int len = ((String) (entry.getValue())).length();
                            if (len <= 12) {
                                return 60;
                            } else if (len == 13) {
                                return 90;
                            } else if (len == 14) {
                                return 120;
                            } else {
                                return 150;
                            }
                        }
                    }
                }
            }
        }
        try {
            Object result = engine.eval(script);
            return result;
        } catch (ScriptException e) {

            return 150;
        }
    }

}
